#include "include.h"
#include "bsp_led.h"

#if LED_DISP_EN
led_func_t bled_func AT(.buf.led);
led_func_t rled_func AT(.buf.led);
gpio_t bled_gpio AT(.buf.led);
gpio_t rled_gpio AT(.buf.led);

led_cb_t led_sync AT(.buf.led);
led_cb_t led_cb AT(.buf.led);
led_cb_t led_lb AT(.buf.led);       //low battery

static u32 timer_tick;

AT(.rodata.led.cfg)
const led_cfg_t led_cfg_connected       = {0x00, 0xff, 1, 0};
AT(.rodata.led.cfg)
const led_cfg_t led_cfg_poweron         = {0x00, 0xaa, 50, 0};
AT(.rodata.led.cfg)
const led_cfg_t led_cfg_pairing         = {0x00, 0xaa, 10, 0};
#if (LED_LOWBAT_EN || RLED_LOWBAT_FOLLOW_EN)
AT(.rodata.led.cfg)
const led_cfg_t led_cfg_lowbat          = {0xaa, 0x00, 0x06, 0x00};     //红灯300ms周期闪烁
AT(.rodata.led.cfg)
const led_cfg_t led_cfg_lowbat_follow   = {0x0a, 0x00, 0x02, 0xff};     //红灯间隔100ms闪2次

AT(.text.led_disp.sta)
void led_set_sta_lowbat(const led_cfg_t *cfg)
{
    LED_PWR_SET_OFF();
    LED_SET_OFF();
    led_set_sta_do(cfg, &led_lb);
}

AT(.text.led_disp.sta)
void led_lowbat(void)
{
    if (!led_cb.lowbat) {
        if (xcfg_cb.led_lowbat_config_en) {
            led_set_sta_lowbat((const led_cfg_t *)&xcfg_cb.led_lowbat);
        } else {
            led_set_sta_lowbat(&led_cfg_lowbat);
        }
        led_cb.lowbat = true;
    }
}
#endif // LED_LOWBAT_EN

AT(.text.led_disp.sta)
void led_bt_connected(void)
{
    //是否配置蓝牙已连接状态LED?
    if (xcfg_cb.led_btconn_config_en) {
        led_set_sta((led_cfg_t *)&xcfg_cb.led_connected);
    } else {
        led_set_sta(&led_cfg_connected);
    }
}

AT(.text.led_disp.sta)
void led_bt_pairing(void)
{
    //是否配置蓝牙已连接状态LED?
    if (xcfg_cb.led_btconn_config_en) {
        led_set_sta((led_cfg_t *)&xcfg_cb.led_pair);
    } else {
        led_set_sta(&led_cfg_pairing);
    }
}

AT(.text.led_disp.sta)
void led_power_up(void)
{
    if (xcfg_cb.led_pwron_config_en) {
        led_set_sta((led_cfg_t *)&xcfg_cb.led_poweron);
    } else {
        led_set_sta(&led_cfg_poweron);
    }
}

AT(.text.led_disp.sta)
bool led_bt_sleep(void)
{
    static u8 cnt = 0;

    cnt++;
    if (cnt >= 10) {
        cnt = 0;
        LED_INIT();
        LED_SET_ON();
        return true;
    } else {
        LED_SET_OFF();
        return false;
    }
}

AT(.text.led_proc.process)
void led_disp_proc(void)
{
    if(sys_cb.led_sta != sys_cb.disp_sta) {
        sys_cb.disp_sta = sys_cb.led_sta;
        switch(sys_cb.led_sta) {
        case LED_USER_POWER_ON:
            led_power_up();
            break;
        case LED_USER_CONN:
            led_bt_connected();
            break;
        case LED_USER_CLEAR_PAIR:
            led_bt_pairing();
            break;
#if (LED_LOWBAT_EN || RLED_LOWBAT_FOLLOW_EN)
        case LED_USER_LOW_BAT:
            led_lowbat();
            break;
#endif
        }
    }
}

AT(.text.led_init.port)
void led_init(void)
{
    LED_INIT();
    LED_PWR_INIT();
    memset(&led_sync, 0, sizeof(led_sync));
    memset(&led_cb, 0, sizeof(led_cb));
    memset(&led_lb, 0, sizeof(led_lb));
}

AT(.text.led_init.func)
void led_func_init(void)
{
#if UART0_PRINTF_SEL == PRINTF_PB3
    if (xcfg_cb.bled_io_sel == 12) {
        xcfg_cb.bled_io_sel = 0;
    }
    if (xcfg_cb.rled_io_sel == 12) {
        xcfg_cb.rled_io_sel = 0;
    }
#endif
    bsp_gpio_cfg_init(&bled_gpio, xcfg_cb.bled_io_sel);
    bsp_gpio_cfg_init(&rled_gpio, xcfg_cb.rled_io_sel);

#if LED_PWR_EN
    if (xcfg_cb.bled_io_sel == xcfg_cb.rled_io_sel) {
        //1个IO推两个灯
        if (bled_gpio.sfr != NULL) {
            sys_cb.port2led_en = 1;
        }
        bled_func.port_init = led2_port_init;
        bled_func.set_on = bled2_set_on;
        bled_func.set_off = bled2_set_off;

        rled_func.port_init = led2_port_init;
        rled_func.set_on = rled2_set_on;
        rled_func.set_off = rled2_set_off;
    } else
#endif // LED_PWR_EN
    {
        sys_cb.port2led_en = 0;
        bled_func.port_init = led_cfg_port_init;
        bled_func.set_on = led_cfg_set_on;
        bled_func.set_off = led_cfg_set_off;

        rled_func.port_init = led_cfg_port_init;
        rled_func.set_on = led_cfg_set_on;
        rled_func.set_off = led_cfg_set_off;
    }
}

AT(.com_text.led_disp)
void led_scan(void)
{
    led_cb_t *s;

    if (!LED_DISP_EN) {
        return;
    }
    if(++timer_tick < 50/5) {
        return;
    }
    timer_tick = 0;

    s = (led_cb.lowbat)? &led_lb : &led_cb;
    if(s->unit == 0 || s->circle == 0) {
        if(led_cb.lowbat){
            led_cb.lowbat = false;
        }
        return;
    }

    u8 bcnt = s->cnt / s->unit;
    if(bcnt <= 7) {
        if (s->bled_sta & BIT(bcnt)) {
            LED_SET_ON();
        } else {
            LED_SET_OFF();
        }
        if (s->rled_sta & BIT(bcnt)) {
            LED_PWR_SET_ON();
        } else {
            LED_PWR_SET_OFF();
        }
    } else {
        //只亮一次
        if(s->circle == 0x7fff) {
            s->unit = 0;
        }
    }

    if(s->cnt < 0xffff) {
        s->cnt++;
        if (s->cnt > s->circle) {
            s->cnt = 0;
        }
    }
}

AT(.com_text.led_disp)
void led_cfg_set_on(gpio_t *g)
{
    led_cfg_set_onoff(g, 1);
}

AT(.com_text.led_disp)
void led_cfg_set_off(gpio_t *g)
{
    led_cfg_set_onoff(g, 0);
}

#if LED_PWR_EN
//一个IO口推两个LED灯
AT(.text.led_init.port)
void led2_port_init(gpio_t *g)
{
    m_led2_port_init(g, !xcfg_cb.port_2led_resless_en);
}

//每ms扫描一次
AT(.com_text.led_disp)
void port_2led_scan(void)
{
    if ((!sys_cb.port2led_en)) {
        return;
    }
    m_port_2led_scan(&bled_gpio);
}

//1个IO推两个灯，充电状态下不进sleep，否则充电灯异常。
AT(.text.led_disp.sta)
bool port_2led_is_sleep_en(void)
{
    if ((sys_cb.port2led_en) && (CHARGE_DC_IN())) {
        return false;
    }
    return true;
}
#endif // LED_PWR_EN

//蓝灯灭
AT(.text.led_disp.sta)
void bled_off(void)
{
    led_cb.bled_sta = 0x00;
    LED_SET_OFF();
}

AT(.text.led_disp.sta)
void rled_off(void)
{
    led_cb.rled_sta = 0x00;
    LED_PWR_SET_OFF();
}

//拔出充电红灯灭
AT(.text.led_disp.sta)
void charge_led_off(void)
{
    LED_PWR_SET_OFF();
}

//充电红灯亮
AT(.text.led_disp.sta)
void charge_led_on(void)
{
    led_cb.bled_sta = 0x00;     //充电关蓝灯亮红灯
    LED_SET_OFF();
    LED_PWR_SET_ON();
}

AT(.text.led_disp.sta) ALIGNED(512)
void led_set_sta_do(const led_cfg_t *cfg, led_cb_t *s)
{
    led_cfg_t sta;
    memcpy(&sta, cfg, sizeof(sta));

    GLOBAL_INT_DISABLE();

    s->rled_sta = sta.redpat;
    s->bled_sta = sta.bluepat;
    s->unit     = sta.unit;
    s->period   = sta.cycle;

    if (s->period == 0xff) {
        s->circle = 0x7fff;
    } else {
        s->circle = s->unit * 8 + s->period;
    }
    s->cnt = 0;
    GLOBAL_INT_RESTORE();
}

AT(.text.led_disp.sta)
void led_set_sta_normal(const led_cfg_t *cfg)
{
    if(!led_cb.lowbat) {
        LED_PWR_SET_OFF();
        LED_SET_OFF();
    }
    led_set_sta_do(cfg, &led_cb);
}

#endif
AT(.text.led_disp.sta)
u8 led_get_cfg_port(void)
{
    if(xcfg_cb.led_disp_en) {
        return xcfg_cb.bled_io_sel; //优先选择蓝灯
    } else if(xcfg_cb.led_pwr_en) {
        return xcfg_cb.rled_io_sel; //其次选择红灯
    }
    return 0;                       //不显示
}
